/*
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    2011 year
 *    Author: Michael Khromov aka MikeDM (Mike D'Morto)
 *    E-Mail: mikedmorto@gmail.com
 */

/*
Плагин для доступа к данным mysql
описание строки инициализации

0 - наименование плагина. должно быть mysql
1 итд итп это параметры
host = хост где находится сервис базы данных
port = порт соединения, по умолчанию 3306
socket = путь до сокета, используется как альтернатива host имеет больший приоритет при соединении
name = имя базы данных
login = логин пользователя
pass = пароль пользователя

перечень обязательных параметров - host или socket, name, login
другие опциональны

*/


#include "libdb_mysql.h"
#include <QDebug>
#include <QApplication>
#include <QTranslator>


bool Libdb_mysql::init(const QStringList &cfg, const QString & lng){
    // порт по умолчанию 3306
    this->dbport=DEFPORT;


    // подключаем перевод.
    QTranslator * trans = new QTranslator();
    if(trans->load(QString("%1/%2/%3.qm").arg(LANG_PREFIX).arg(PLUGIN_NAME).arg(lng))){
            QCoreApplication::installTranslator(trans);
            emit this->sigPutLog(PLUGIN_NAME,3,QString(tr("Debug: success translate %1")).arg(lng));
        }else{
            emit this->sigPutLog(PLUGIN_NAME,1,QString("fail translate %1").arg(lng));
        }

    emit this->sigPutLog(PLUGIN_NAME,2,tr("Info: start init"));
    // парсим параметры инициализации
    emit this->sigPutLog(PLUGIN_NAME,3,tr("Debug: parsing config string"));

    if(cfg.size() > 1){
        // если параметров инициализации базы больше чем название базы, то есть смысл продолжать
        for(int i = 1; i < cfg.size() ; i++){
            // проверяем наличие всех параметров
            QStringList tt = cfg.at(i).split("=");
            if(tt.at(0)=="host"){
                if(tt.size() > 1){
                    this->dbhost=cfg.at(i).split("=").at(1);
                }
            }else{
                if(tt.at(0)=="socket"){
                    if(tt.size() > 1){
                        this->dbsocket=cfg.at(i).split("=").at(1);
                    }
                }else{
                    if(tt.at(0)=="name"){
                        if(tt.size() > 1){
                            this->dbname=cfg.at(i).split("=").at(1);
                        }
                    }else{
                        if(tt.at(0)=="user"){
                            if(tt.size() > 1){
                                this->dbuser=cfg.at(i).split("=").at(1);
                            }
                        }else{
                            if(tt.at(0)=="pass"){
                                if(tt.size() > 1){
                                    this->dbpass=cfg.at(i).split("=").at(1);
                                }
                            }else{
                                if(tt.at(0)=="port"){
                                    if(tt.size() > 1){
                                        this->dbport=cfg.at(i).split("=").at(1).toInt();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // проверяем что получилось, важно что бы был либо host либо socket если из них никого, печалька и ошибка инициализациии
    if(this->dbhost.size()==0){
        // внезапно кто то забыл про хост, проверяем сокет, вдруг там будет то что надо
        if(this->dbsocket.size()==0){
            // бида пичаль, и сокет забыли, ругаемся и завершаем инициализацию
            this->lastError=tr("host or socket not set");
            return false;
        }
    }

    // дальше имя базы должно быть обязательно, и юзер, а вот пасс опционален.
    if(this->dbname.size()==0){
        this->lastError=tr("database name not set");
        return false;
    }
    if(this->dbuser.size()==0){
        this->lastError=tr("database user not set");
        return false;
    }

    emit this->sigPutLog(PLUGIN_NAME,3,tr("Debug: start dbworker thread"));
    // выставляем флаги для ловли блох =)
    this->fInitErr=false;
    this->fInitOk=false;

    // если все гуд стартуем второй поток и в нем инициализируем соединение с базой
    this->worker = new dbworker(dbhost,dbport,dbsocket, dbname, dbuser, dbpass);
    connect(this->worker,SIGNAL(sigPutLog(QString,int,QString)),
            this,SLOT(slotFor_putlog(QString,int,QString)),Qt::DirectConnection);
    connect(this->worker,SIGNAL(sigInit(bool)),
            this,SLOT(slotInit(bool)),Qt::DirectConnection);
    connect(this->worker,SIGNAL(sigError(QString,QString)),
            this,SLOT(slotErrorW(QString,QString)),Qt::DirectConnection);
    connect(this->worker,SIGNAL(sigFinish(QString,int,Mdata*)),
            this,SLOT(slotFinishW(QString,int,Mdata*)),Qt::DirectConnection);




    // уходим в циклическое ожидание инициализации соединения
    while(true){
        QApplication::processEvents();
        if(this->fInitErr or this->fInitOk){
            // пролетело событие инициализации worker
            break;
        }

    }
    // проверяем, если инициализация сорвалась, то надо поругаться
    if(this->fInitErr){
        this->lastError=this->worker->getLastError();
        emit this->sigPutLog(PLUGIN_NAME,3,tr("Debug: failure connect to database - %1").arg(
                                 this->lastError));
        return false;

    }

    // если зацепились с базой значит все гуд.
    emit this->sigPutLog(PLUGIN_NAME,3,tr("Debug: success connect to database"));
    return true;
}

QString Libdb_mysql::getlastError(){
    // возвращаем последнюю ошибку в работе библиотеки. сие есть сущая небходимость =)
    return this->lastError;
}

void Libdb_mysql::slotInit(bool init){
    // прилетел сигнал об инициализации воркера потока, глядим как оно там =))
    if(init){
        this->fInitOk=true;
    }else{
        this->fInitErr=true;
    }
}

void Libdb_mysql::slotFor_putlog(const QString &owner, int level, const QString &text){
    // передаем событие в лог из потока dbworker
    emit this->sigPutLog(owner,level,text);
}

void Libdb_mysql::slotFreeRes(int id){
    this->worker->freeRes(id);
}

void Libdb_mysql::slotQuery(const QString &pl_name, const QString &metaf_name, QStringList &params){
    // прилетел асинхронный запрос
    MFitem * item = new MFitem;
    item->pl_name=pl_name;
    item->mfname=metaf_name;
    item->params=params;
    this->worker->putMFun(item);

}

void Libdb_mysql::slotErrorW(const QString &pl_name, const QString &errtext){
    // упала ошибка из потока, какой то из запросав дал  сбой, отправляем дальше
    emit this->sigError(pl_name,errtext);
}

void Libdb_mysql::slotFinishW(const QString & pl_name,int id, Mdata *data){
    // упал результат асинхронной функции
    // толкаем его в мир
    emit this->sigFinish(pl_name,id,data);
}

void Libdb_mysql::slotQueryCync(const QString &pl_name, const QString &metaf_name, QStringList &params){

}

void Libdb_mysql::slotStartSync(const QString &pl_name){

}

void Libdb_mysql::slotStop(){
    this->worker->stopT();
}

void Libdb_mysql::slotStopSync(const QString &pl_name){

}


Q_EXPORT_PLUGIN2(iDatabase,Libdb_mysql)
